<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Out-of-focus Deblur Filter</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d9/df8/tutorial_root.html">OpenCV Tutorials</a></li><li class="navelem"><a class="el" href="../../d7/da8/tutorial_table_of_content_imgproc.html">Image Processing (imgproc module)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Out-of-focus Deblur Filter </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>Prev Tutorial:</b> <a class="el" href="../../d2/dbd/tutorial_distance_transform.html">Image Segmentation with Distance Transform and Watershed Algorithm</a></p>
<p><b>Next Tutorial:</b> <a class="el" href="../../d1/dfd/tutorial_motion_deblur_filter.html">Motion Deblur Filter</a></p>
<table class="doxtable">
<tr>
<th align="right"></th><th align="left"></th></tr>
<tr>
<td align="right">Original author </td><td align="left">Karpushin Vladislav </td></tr>
<tr>
<td align="right">Compatibility </td><td align="left">OpenCV &gt;= 3.0 </td></tr>
</table>
<h2>Goal </h2>
<p>In this tutorial you will learn:</p>
<ul>
<li>what a degradation image model is</li>
<li>what the PSF of an out-of-focus image is</li>
<li>how to restore a blurred image</li>
<li>what is a Wiener filter</li>
</ul>
<h2>Theory </h2>
<dl class="section note"><dt>Note</dt><dd>The explanation is based on the books <a class="el" href="../../d0/de3/citelist.html#CITEREF_gonzalez">[94]</a> and <a class="el" href="../../d0/de3/citelist.html#CITEREF_gruzman">[300]</a>. Also, you can refer to Matlab's tutorial <a href="https://www.mathworks.com/help/images/image-deblurring.html">Image Deblurring in Matlab</a> and the article <a href="http://yuzhikov.com/articles/BlurredImagesRestoration1.htm">SmartDeblur</a>. </dd>
<dd>
The out-of-focus image on this page is a real world image. The out-of-focus was achieved manually by camera optics.</dd></dl>
<h3>What is a degradation image model?</h3>
<p>Here is a mathematical model of the image degradation in frequency domain representation:</p>
<p class="formulaDsp">
\[S = H\cdot U + N\]
</p>
<p>where \(S\) is a spectrum of blurred (degraded) image, \(U\) is a spectrum of original true (undegraded) image, \(H\) is a frequency response of point spread function (PSF), \(N\) is a spectrum of additive noise.</p>
<p>The circular PSF is a good approximation of out-of-focus distortion. Such a PSF is specified by only one parameter - radius \(R\). Circular PSF is used in this work.</p>
<div class="image">
<img src="../../psf.png" alt="psf.png"/>
<div class="caption">
Circular point spread function</div></div>
 <h3>How to restore a blurred image?</h3>
<p>The objective of restoration (deblurring) is to obtain an estimate of the original image. The restoration formula in frequency domain is:</p>
<p class="formulaDsp">
\[U&#39; = H_w\cdot S\]
</p>
<p>where \(U&#39;\) is the spectrum of estimation of original image \(U\), and \(H_w\) is the restoration filter, for example, the Wiener filter.</p>
<h3>What is the Wiener filter?</h3>
<p>The Wiener filter is a way to restore a blurred image. Let's suppose that the PSF is a real and symmetric signal, a power spectrum of the original true image and noise are not known, then a simplified Wiener formula is:</p>
<p class="formulaDsp">
\[H_w = \frac{H}{|H|^2+\frac{1}{SNR}} \]
</p>
<p>where \(SNR\) is signal-to-noise ratio.</p>
<p>So, in order to recover an out-of-focus image by Wiener filter, it needs to know the \(SNR\) and \(R\) of the circular PSF.</p>
<h2>Source code </h2>
<p>You can find source code in the <code>samples/cpp/tutorial_code/ImgProc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.cpp</code> of the OpenCV source code library.</p>
<div class="fragment"><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d1/d4f/imgproc_2include_2opencv2_2imgproc_8hpp.html">opencv2/imgproc.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d6/d87/imgcodecs_8hpp.html">opencv2/imgcodecs.hpp</a>&quot;</span></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span><a class="code" href="../../d2/d75/namespacecv.html">cv</a>;</div><div class="line"><span class="keyword">using namespace </span>std;</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> help();</div><div class="line"><span class="keywordtype">void</span> calcPSF(<a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <a class="code" href="../../d6/d50/classcv_1_1Size__.html">Size</a> filterSize, <span class="keywordtype">int</span> R);</div><div class="line"><span class="keywordtype">void</span> fftshift(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg);</div><div class="line"><span class="keywordtype">void</span> filter2DFreq(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; H);</div><div class="line"><span class="keywordtype">void</span> calcWnrFilter(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; input_h_PSF, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; output_G, <span class="keywordtype">double</span> nsr);</div><div class="line"></div><div class="line"><span class="keyword">const</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> keys =</div><div class="line"><span class="stringliteral">&quot;{help h usage ? |             | print this message   }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{image          |original.JPG | input image name     }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{R              |53           | radius               }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{SNR            |5200         | signal to noise ratio}&quot;</span></div><div class="line">;</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> *argv[])</div><div class="line">{</div><div class="line">    help();</div><div class="line">    <a class="code" href="../../d0/d2e/classcv_1_1CommandLineParser.html">CommandLineParser</a> parser(argc, argv, keys);</div><div class="line">    <span class="keywordflow">if</span> (parser.has(<span class="stringliteral">&quot;help&quot;</span>))</div><div class="line">    {</div><div class="line">        parser.printMessage();</div><div class="line">        <span class="keywordflow">return</span> 0;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keywordtype">int</span> R = parser.get&lt;<span class="keywordtype">int</span>&gt;(<span class="stringliteral">&quot;R&quot;</span>);</div><div class="line">    <span class="keywordtype">int</span> snr = parser.get&lt;<span class="keywordtype">int</span>&gt;(<span class="stringliteral">&quot;SNR&quot;</span>);</div><div class="line">    <span class="keywordtype">string</span> strInFileName = parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;(<span class="stringliteral">&quot;image&quot;</span>);</div><div class="line"></div><div class="line">    <span class="keywordflow">if</span> (!parser.check())</div><div class="line">    {</div><div class="line">        parser.printErrors();</div><div class="line">        <span class="keywordflow">return</span> 0;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> imgIn;</div><div class="line">    imgIn = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>(strInFileName, <a class="code" href="../../d8/d6a/group__imgcodecs__flags.html#gga61d9b0126a3e57d9277ac48327799c80ae29981cfc153d3b0cef5c0daeedd2125">IMREAD_GRAYSCALE</a>);</div><div class="line">    <span class="keywordflow">if</span> (imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abbec3525a852e77998aba034813fded4">empty</a>()) <span class="comment">//check whether the image is loaded or not</span></div><div class="line">    {</div><div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;ERROR : Image cannot be loaded..!!&quot;</span> &lt;&lt; endl;</div><div class="line">        <span class="keywordflow">return</span> -1;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> imgOut;</div><div class="line"></div><div class="line">    <span class="comment">// it needs to process even image only</span></div><div class="line">    <a class="code" href="../../d2/d44/classcv_1_1Rect__.html">Rect</a> roi = <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a> &amp; -2, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a> &amp; -2);</div><div class="line"></div><div class="line">    <span class="comment">//Hw calculation (start)</span></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> Hw, h;</div><div class="line">    calcPSF(h, roi.<a class="code" href="../../d2/d44/classcv_1_1Rect__.html#ab0c92d80e25e22be48c0110c5200da1e">size</a>(), R);</div><div class="line">    calcWnrFilter(h, Hw, 1.0 / <span class="keywordtype">double</span>(snr));</div><div class="line">    <span class="comment">//Hw calculation (stop)</span></div><div class="line"></div><div class="line">    <span class="comment">// filtering (start)</span></div><div class="line">    filter2DFreq(imgIn(roi), imgOut, Hw);</div><div class="line">    <span class="comment">// filtering (stop)</span></div><div class="line"><span class="comment"></span></div><div class="line">    imgOut.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adf88c60c5b4980e05bb556080916978b">convertTo</a>(imgOut, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga32b18d904ee2b1731a9416a8eef67d06">CV_8U</a>);</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1b6a396a456c8b6c6e4afd8591560d80">normalize</a>(imgOut, imgOut, 0, 255, <a class="code" href="../../d2/de8/group__core__array.html#ggad12cefbcb5291cf958a85b4b67b6149fa9f0c1c342a18114d47b516a88e29822e">NORM_MINMAX</a>);</div><div class="line">    <a class="code" href="../../d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce">imwrite</a>(<span class="stringliteral">&quot;result.jpg&quot;</span>, imgOut);</div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> help()</div><div class="line">{</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;2018-07-12&quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;DeBlur_v8&quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;You will learn how to recover an out-of-focus image by Wiener filter&quot;</span> &lt;&lt; endl;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> calcPSF(<a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <a class="code" href="../../d6/d50/classcv_1_1Size__.html">Size</a> filterSize, <span class="keywordtype">int</span> R)</div><div class="line">{</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> h(filterSize, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line">    <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> point(filterSize.<a class="code" href="../../d6/d50/classcv_1_1Size__.html#abfe0367b32c407ddccf5ddf92667c73d">width</a> / 2, filterSize.<a class="code" href="../../d6/d50/classcv_1_1Size__.html#a1d289dce6b5d8006a54f3ee0259fc545">height</a> / 2);</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#gaf10604b069374903dbd0f0488cb43670">circle</a>(h, point, R, 255, -1, 8);</div><div class="line">    <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">Scalar</a> summa = <a class="code" href="../../d2/de8/group__core__array.html#ga716e10a2dd9e228e4d3c95818f106722">sum</a>(h);</div><div class="line">    outputImg = h / summa[0];</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> fftshift(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg)</div><div class="line">{</div><div class="line">    outputImg = inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>();</div><div class="line">    <span class="keywordtype">int</span> cx = outputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a> / 2;</div><div class="line">    <span class="keywordtype">int</span> cy = outputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a> / 2;</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q0(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q1(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(cx, 0, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q2(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, cy, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q3(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(cx, cy, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> tmp;</div><div class="line">    q0.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(tmp);</div><div class="line">    q3.copyTo(q0);</div><div class="line">    tmp.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(q3);</div><div class="line">    q1.copyTo(tmp);</div><div class="line">    q2.copyTo(q1);</div><div class="line">    tmp.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(q2);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> filter2DFreq(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; H)</div><div class="line">{</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> planes[2] = { <a class="code" href="../../df/dfc/classcv_1_1Mat__.html">Mat_&lt;float&gt;</a>(inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>()), <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>(inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexI;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planes, 2, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">dft</a>(complexI, complexI, <a class="code" href="../../d2/de8/group__core__array.html#ggaf4dde112b483b38175621befedda1f1ca74746fb171aa4bfc08ace28d73f52375">DFT_SCALE</a>);</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> planesH[2] = { <a class="code" href="../../df/dfc/classcv_1_1Mat__.html">Mat_&lt;float&gt;</a>(H.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>()), <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>(H.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexH;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planesH, 2, complexH);</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexIH;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga3ab38646463c59bf0ce962a9d51db64f">mulSpectrums</a>(complexI, complexH, complexIH, 0);</div><div class="line"></div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1">idft</a>(complexIH, complexIH);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a">split</a>(complexIH, planes);</div><div class="line">    outputImg = planes[0];</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> calcWnrFilter(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; input_h_PSF, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; output_G, <span class="keywordtype">double</span> nsr)</div><div class="line">{</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> h_PSF_shifted;</div><div class="line">    fftshift(input_h_PSF, h_PSF_shifted);</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> planes[2] = { <a class="code" href="../../df/dfc/classcv_1_1Mat__.html">Mat_&lt;float&gt;</a>(h_PSF_shifted.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>()), <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>(h_PSF_shifted.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexI;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planes, 2, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">dft</a>(complexI, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a">split</a>(complexI, planes);</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> denom;</div><div class="line">    <a class="code" href="../../d7/dcc/group__core__utils__softfloat.html#ga8bc36646a43b82baa15f151a973fb0c5">pow</a>(<a class="code" href="../../d2/d75/namespacecv.html#af6df65b17fb11af6d34634b6dfa44683">abs</a>(planes[0]), 2, denom);</div><div class="line">    denom += nsr;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga6db555d30115642fedae0cda05604874">divide</a>(planes[0], denom, output_G);</div><div class="line">}</div></div><!-- fragment --><h2>Explanation </h2>
<p>An out-of-focus image recovering algorithm consists of PSF generation, Wiener filter generation and filtering a blurred image in frequency domain: </p><div class="fragment"><div class="line">    <span class="comment">// it needs to process even image only</span></div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a> roi = <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a> &amp; -2, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a> &amp; -2);</div><div class="line"></div><div class="line">    <span class="comment">//Hw calculation (start)</span></div><div class="line">    Mat Hw, h;</div><div class="line">    calcPSF(h, roi.size(), R);</div><div class="line">    calcWnrFilter(h, Hw, 1.0 / <span class="keywordtype">double</span>(snr));</div><div class="line">    <span class="comment">//Hw calculation (stop)</span></div><div class="line"></div><div class="line">    <span class="comment">// filtering (start)</span></div><div class="line">    filter2DFreq(imgIn(roi), imgOut, Hw);</div><div class="line">    <span class="comment">// filtering (stop)</span></div></div><!-- fragment --><p> A function calcPSF() forms a circular PSF according to input parameter radius \(R\): </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> calcPSF(Mat&amp; outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga346f563897249351a34549137c8532a0">Size</a> filterSize, <span class="keywordtype">int</span> R)</div><div class="line">{</div><div class="line">    Mat h(filterSize, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> point(filterSize.width / 2, filterSize.height / 2);</div><div class="line">    <a class="code" href="../../d9/db7/group__datasets__gr.html#gga610754124ced68d1f05760b5948fbb76a6f0d8b2d9e3e947b2a5c1eff9e81ee95">circle</a>(h, point, R, 255, -1, 8);</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a> summa = <a class="code" href="../../d2/de8/group__core__array.html#ga716e10a2dd9e228e4d3c95818f106722">sum</a>(h);</div><div class="line">    outputImg = h / summa[0];</div><div class="line">}</div></div><!-- fragment --><p> A function calcWnrFilter() synthesizes the simplified Wiener filter \(H_w\) according to the formula described above: </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> calcWnrFilter(<span class="keyword">const</span> Mat&amp; input_h_PSF, Mat&amp; output_G, <span class="keywordtype">double</span> nsr)</div><div class="line">{</div><div class="line">    Mat h_PSF_shifted;</div><div class="line">    fftshift(input_h_PSF, h_PSF_shifted);</div><div class="line">    Mat planes[2] = { Mat_&lt;float&gt;(h_PSF_shifted.clone()), Mat::zeros(h_PSF_shifted.size(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    Mat complexI;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planes, 2, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">dft</a>(complexI, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a">split</a>(complexI, planes);</div><div class="line">    Mat denom;</div><div class="line">    <a class="code" href="../../d7/dcc/group__core__utils__softfloat.html#ga8bc36646a43b82baa15f151a973fb0c5">pow</a>(<a class="code" href="../../d1/d10/classcv_1_1MatExpr.html#a30843fc6c148a00f5d300a7f43f3fbdc">abs</a>(planes[0]), 2, denom);</div><div class="line">    denom += nsr;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga6db555d30115642fedae0cda05604874">divide</a>(planes[0], denom, output_G);</div><div class="line">}</div></div><!-- fragment --><p> A function fftshift() rearranges the PSF. This code was just copied from the tutorial <a class="el" href="../../d8/d01/tutorial_discrete_fourier_transform.html">Discrete Fourier Transform</a>: </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> fftshift(<span class="keyword">const</span> Mat&amp; inputImg, Mat&amp; outputImg)</div><div class="line">{</div><div class="line">    outputImg = inputImg.clone();</div><div class="line">    <span class="keywordtype">int</span> cx = outputImg.cols / 2;</div><div class="line">    <span class="keywordtype">int</span> cy = outputImg.rows / 2;</div><div class="line">    Mat q0(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, cx, cy));</div><div class="line">    Mat q1(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(cx, 0, cx, cy));</div><div class="line">    Mat q2(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, cy, cx, cy));</div><div class="line">    Mat q3(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(cx, cy, cx, cy));</div><div class="line">    Mat tmp;</div><div class="line">    q0.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(tmp);</div><div class="line">    q3.copyTo(q0);</div><div class="line">    tmp.copyTo(q3);</div><div class="line">    q1.copyTo(tmp);</div><div class="line">    q2.copyTo(q1);</div><div class="line">    tmp.copyTo(q2);</div><div class="line">}</div></div><!-- fragment --><p> A function filter2DFreq() filters the blurred image in the frequency domain: </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> filter2DFreq(<span class="keyword">const</span> Mat&amp; inputImg, Mat&amp; outputImg, <span class="keyword">const</span> Mat&amp; H)</div><div class="line">{</div><div class="line">    Mat planes[2] = { Mat_&lt;float&gt;(inputImg.clone()), Mat::zeros(inputImg.size(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    Mat complexI;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planes, 2, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">dft</a>(complexI, complexI, <a class="code" href="../../d2/de8/group__core__array.html#ggaf4dde112b483b38175621befedda1f1ca74746fb171aa4bfc08ace28d73f52375">DFT_SCALE</a>);</div><div class="line"></div><div class="line">    Mat planesH[2] = { Mat_&lt;float&gt;(H.clone()), Mat::zeros(H.size(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    Mat complexH;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planesH, 2, complexH);</div><div class="line">    Mat complexIH;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga3ab38646463c59bf0ce962a9d51db64f">mulSpectrums</a>(complexI, complexH, complexIH, 0);</div><div class="line"></div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1">idft</a>(complexIH, complexIH);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a">split</a>(complexIH, planes);</div><div class="line">    outputImg = planes[0];</div><div class="line">}</div></div><!-- fragment --> <h2>Result </h2>
<p>Below you can see the real out-of-focus image: </p><div class="image">
<img src="../../original.jpg" alt="original.jpg"/>
<div class="caption">
Out-of-focus image</div></div>
<p>And the following result has been computed with \(R\) = 53 and \(SNR\) = 5200 parameters: </p><div class="image">
<img src="../../recovered.jpg" alt="recovered.jpg"/>
<div class="caption">
The restored (deblurred) image</div></div>
<p> The Wiener filter was used, and values of \(R\) and \(SNR\) were selected manually to give the best possible visual result. We can see that the result is not perfect, but it gives us a hint to the image's content. With some difficulty, the text is readable.</p>
<dl class="section note"><dt>Note</dt><dd>The parameter \(R\) is the most important. So you should adjust \(R\) first, then \(SNR\). </dd>
<dd>
Sometimes you can observe the ringing effect in a restored image. This effect can be reduced with several methods. For example, you can taper input image edges.</dd></dl>
<p>You can also find a quick video demonstration of this on <a href="https://youtu.be/0bEcE4B0XP4">YouTube</a>. </p><div align='center'><iframe title='Video' width='560' height='349' src='https://www.youtube.com/embed/0bEcE4B0XP4?rel=0' frameborder='0' align='middle' allowfullscreen></iframe></div><h2>References </h2>
<ul>
<li><a href="https://www.mathworks.com/help/images/image-deblurring.html">Image Deblurring in Matlab</a> - Image Deblurring in Matlab</li>
<li><a href="http://yuzhikov.com/articles/BlurredImagesRestoration1.htm">SmartDeblur</a> - SmartDeblur site </li>
</ul>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:36 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
